using WeatherSystem.API.Models;
using WeatherSystem.API.Specifications;
using WeatherSystem.API.Extensions;

namespace WeatherSystem.API.Repositories
{
    /// <summary>
    /// 统计Repository旧接口适配器
    /// 用于向后兼容新的读写分离架构
    /// </summary>
    public class LegacyStatisticsAdapter : IStatisticsRepository
    {
        private readonly IReadRepository<StatisticsEntry> _readRepository;
        private readonly IWriteRepository<StatisticsEntry> _writeRepository;

        public LegacyStatisticsAdapter(IReadRepository<StatisticsEntry> readRepository, IWriteRepository<StatisticsEntry> writeRepository)
        {
            _readRepository = readRepository;
            _writeRepository = writeRepository;
        }

        private static object ConvertRawValueToTyped(string rawValue, string dataType)
        {
            return dataType switch
            {
                "decimal" => decimal.Parse(rawValue),
                "int" => int.Parse(rawValue),
                "boolean" => bool.Parse(rawValue),
                _ => rawValue
            };
        }

        public async Task<StatisticsEntry?> GetLatestByCityAndMetricAsync(Guid cityId, string metric)
        {
            var spec = new StatisticsSpecification(cityId, metric);
            var result = await _readRepository.GetBySpecificationAsync(spec);
            return result.OrderByDescending(s => s.StatisticDate).FirstOrDefault();
        }

        public async Task<List<StatisticsEntry>> GetByCityAndDateAsync(Guid cityId, DateTime date)
        {
            var startDate = date.Date;
            var endDate = date.Date.AddDays(1).AddSeconds(-1);
            var spec = new StatisticsSpecification(cityId, null, startDate, endDate);
            var result = await _readRepository.GetBySpecificationAsync(spec);
            return result.ToList();
        }

        public async Task<List<StatisticsEntry>> GetByCityAndDateRangeAsync(Guid cityId, DateTime startDate, DateTime endDate)
        {
            var spec = new StatisticsSpecification(cityId, null, startDate, endDate);
            var result = await _readRepository.GetBySpecificationAsync(spec);
            return result.ToList();
        }

        public async Task<Dictionary<string, object>> GetCityStatisticsAsync(Guid cityId, DateTime startDate, DateTime endDate)
        {
            var spec = new StatisticsSpecification(cityId, null, startDate, endDate);
            var stats = await _readRepository.GetBySpecificationAsync(spec);

            var result = new Dictionary<string, object>();
            foreach (var group in stats.GroupBy(s => s.StatisticType))
            {
                var latestStat = group.OrderByDescending(s => s.StatisticDate).FirstOrDefault();
                var latestValue = latestStat?.Values.FirstOrDefault();
                result[group.Key] = latestValue != null ? ConvertRawValueToTyped(latestValue.RawValue, latestValue.DataType) : (object)"0";
            }

            return result;
        }

        public async Task<List<Dictionary<string, object>>> GetCityComparisonAsync(List<Guid> cityIds, DateTime date)
        {
            var startDate = date.Date;
            var endDate = date.Date.AddDays(1).AddSeconds(-1);

            var results = new List<Dictionary<string, object>>();
            foreach (var cityId in cityIds)
            {
                var spec = new StatisticsSpecification(cityId, null, startDate, endDate);
                var cityStats = await _readRepository.GetBySpecificationAsync(spec);

                var statsDict = new Dictionary<string, object>
                {
                    ["CityId"] = cityId,
                    ["Date"] = date
                };

                foreach (var stat in cityStats)
                {
                    foreach (var value in stat.Values)
                    {
                        statsDict[value.MetricKey] = ConvertRawValueToTyped(value.RawValue, value.DataType);
                    }
                }

                results.Add(statsDict);
            }

            return results;
        }

        public async Task<object> GetWeatherTrendAsync(Guid cityId, int days)
        {
            var endDate = DateTime.Now;
            var startDate = endDate.AddDays(-days);

            var spec = new StatisticsSpecification(cityId, null, startDate, endDate);
            var stats = await _readRepository.GetBySpecificationAsync(spec);

            return stats
                .SelectMany(s => s.Values.Select(v => new { s.StatisticDate, v.MetricKey, v.RawValue, v.DataType }))
                .GroupBy(x => x.MetricKey)
                .ToDictionary(
                    g => g.Key,
                    g => g.OrderBy(x => x.StatisticDate).Select(x => new { Timestamp = x.StatisticDate, Value = ConvertRawValueToTyped(x.RawValue, x.DataType) }).ToList()
                );
        }

        public async Task<PagedResult<Dictionary<string, object>>> GetStatisticsPagedAsync(
            int page, int pageSize, Guid? cityId = null,
            DateTime? startDate = null, DateTime? endDate = null)
        {
            var spec = new StatisticsSpecification(cityId, startDate, endDate);
            var statistics = await _readRepository.GetBySpecificationAsync(spec);

            var data = statistics
                .Skip((page - 1) * pageSize)
                .Take(pageSize)
                .Select(s => s.ToDictionary())
                .ToList();

            var totalCount = await _readRepository.CountAsync(spec);

            return new PagedResult<Dictionary<string, object>>(data, totalCount, page, pageSize);
        }

        public async Task<List<StatisticsEntry>> GetStatisticsRangeAsync(Guid cityId, string metric, DateTime startDate, DateTime endDate)
        {
            var spec = new StatisticsSpecification(cityId, metric, startDate, endDate);
            var result = await _readRepository.GetBySpecificationAsync(spec);
            return result.ToList();
        }

        // 实现基础接口方法
        public async Task<StatisticsEntry?> GetByIdAsync(Guid id)
        {
            return await _readRepository.GetByIdAsync(id);
        }

        public async Task<IEnumerable<StatisticsEntry>> GetAllAsync()
        {
            var result = await _readRepository.GetAllAsync();
            return result.ToList();
        }

        public async Task<IEnumerable<StatisticsEntry>> FindAsync(System.Linq.Expressions.Expression<Func<StatisticsEntry, bool>> predicate)
        {
            var spec = new StatisticsSpecification(predicate);
            var result = await _readRepository.GetBySpecificationAsync(spec);
            return result.ToList();
        }

        public async Task AddAsync(StatisticsEntry entity)
        {
            await _writeRepository.AddAsync(entity);
        }

        public async Task AddRangeAsync(IEnumerable<StatisticsEntry> entities)
        {
            await _writeRepository.AddRangeAsync(entities);
        }

        public async Task UpdateAsync(StatisticsEntry entity)
        {
            await _writeRepository.UpdateAsync(entity);
        }

        public async Task UpdateRangeAsync(IEnumerable<StatisticsEntry> entities)
        {
            await _writeRepository.UpdateRangeAsync(entities);
        }

        public async Task DeleteAsync(StatisticsEntry entity)
        {
            await _writeRepository.DeleteAsync(entity);
        }

        public async Task DeleteRangeAsync(IEnumerable<StatisticsEntry> entities)
        {
            await _writeRepository.DeleteRangeAsync(entities);
        }

        public async Task<int> CountAsync(System.Linq.Expressions.Expression<Func<StatisticsEntry, bool>>? predicate = null)
        {
            var spec = predicate != null ? new StatisticsSpecification(predicate) : null;
            return await _readRepository.CountAsync(spec);
        }

        // 实现IReadRepository接口的新方法
        public async Task<StatisticsEntry?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
        {
            return await _readRepository.GetByIdAsync(id, cancellationToken);
        }

        public async Task<IEnumerable<StatisticsEntry>> GetAllAsync(CancellationToken cancellationToken = default)
        {
            var result = await _readRepository.GetAllAsync(cancellationToken);
            return result.ToList();
        }

        public async Task<IEnumerable<StatisticsEntry>> GetBySpecificationAsync(ISpecification<StatisticsEntry> specification, CancellationToken cancellationToken = default)
        {
            var result = await _readRepository.GetBySpecificationAsync(specification, cancellationToken);
            return result.ToList();
        }

        public async Task<StatisticsEntry?> GetSingleBySpecificationAsync(ISpecification<StatisticsEntry> specification, CancellationToken cancellationToken = default)
        {
            return await _readRepository.GetSingleBySpecificationAsync(specification, cancellationToken);
        }

        public async Task<int> CountAsync(ISpecification<StatisticsEntry>? specification = null, CancellationToken cancellationToken = default)
        {
            return await _readRepository.CountAsync(specification, cancellationToken);
        }

        public async Task<bool> AnyAsync(ISpecification<StatisticsEntry>? specification = null, CancellationToken cancellationToken = default)
        {
            return await _readRepository.AnyAsync(specification, cancellationToken);
        }

        public async Task<PagedResult<StatisticsEntry>> GetPagedAsync(int page, int pageSize, ISpecification<StatisticsEntry>? specification = null, CancellationToken cancellationToken = default)
        {
            return await _readRepository.GetPagedAsync(page, pageSize, specification, cancellationToken);
        }

        public async Task<IEnumerable<TResult>> GetProjectedAsync<TResult>(System.Linq.Expressions.Expression<Func<StatisticsEntry, TResult>> projection, ISpecification<StatisticsEntry>? specification = null, CancellationToken cancellationToken = default)
        {
            var result = await _readRepository.GetProjectedAsync(projection, specification, cancellationToken);
            return result.ToList();
        }

        public async Task<PagedResult<TResult>> GetProjectedPagedAsync<TResult>(System.Linq.Expressions.Expression<Func<StatisticsEntry, TResult>> projection, int page, int pageSize, ISpecification<StatisticsEntry>? specification = null, CancellationToken cancellationToken = default)
        {
            return await _readRepository.GetProjectedPagedAsync(projection, page, pageSize, specification, cancellationToken);
        }

        // 实现IWriteRepository接口的新方法
        public async Task<StatisticsEntry> AddAsync(StatisticsEntry entity, CancellationToken cancellationToken = default)
        {
            return await _writeRepository.AddAsync(entity, cancellationToken);
        }

        public async Task<IEnumerable<StatisticsEntry>> AddRangeAsync(IEnumerable<StatisticsEntry> entities, CancellationToken cancellationToken = default)
        {
            var result = await _writeRepository.AddRangeAsync(entities, cancellationToken);
            return result.ToList();
        }

        public async Task UpdateAsync(StatisticsEntry entity, CancellationToken cancellationToken = default)
        {
            await _writeRepository.UpdateAsync(entity, cancellationToken);
        }

        public async Task UpdateRangeAsync(IEnumerable<StatisticsEntry> entities, CancellationToken cancellationToken = default)
        {
            await _writeRepository.UpdateRangeAsync(entities, cancellationToken);
        }

        public async Task DeleteAsync(StatisticsEntry entity, CancellationToken cancellationToken = default)
        {
            await _writeRepository.DeleteAsync(entity, cancellationToken);
        }

        public async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default)
        {
            await _writeRepository.DeleteAsync(id, cancellationToken);
        }

        public async Task DeleteRangeAsync(IEnumerable<StatisticsEntry> entities, CancellationToken cancellationToken = default)
        {
            await _writeRepository.DeleteRangeAsync(entities, cancellationToken);
        }

        public async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
        {
            return await _writeRepository.SaveChangesAsync(cancellationToken);
        }
    }
}